package com.lambert.gingko.watermark.strategy.impl;

import com.lambert.gingko.watermark.annotation.FileProcessor;
import com.lambert.gingko.watermark.enums.FileType;
import com.lambert.gingko.watermark.model.WatermarkConfig;
import com.lambert.gingko.watermark.strategy.AbstWatermarkProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * Excel文件水印处理器
 * @author lambert
 * @since  2025/08/31
 */
@FileProcessor(FileType.EXCEL)
@Slf4j
public class ExcelWatermarkProcessor extends AbstWatermarkProcessor {

    @Override
    protected void doProcess(InputStream is, File outputFile , String extension, WatermarkConfig config) throws Exception {
        boolean isXlsx = "xlsx".equalsIgnoreCase(extension);

        try (Workbook workbook = isXlsx ? new XSSFWorkbook(is) : new HSSFWorkbook(is);
             FileOutputStream os = new FileOutputStream(outputFile)
        ) {
            // 生成文本图片
            byte[] imageBytes = textToImage(config);
            int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);

            // 遍历所有工作表添加水印
            for (Sheet sheet : workbook) {
                if (isXlsx) {
                    processXssfSheet((XSSFSheet) sheet, (XSSFWorkbook) workbook, pictureIdx, config);
                } else {
                    processHssfSheet((HSSFSheet) sheet, (HSSFWorkbook) workbook, pictureIdx, config);
                }
            }
            // 写入输出文件
            workbook.write(os);
        }
    }

    @Override
    public FileType getSupportedType() {
        return FileType.EXCEL;
    }
    /**
     * 处理XSSF格式（.xlsx）工作表
     */
    private void processXssfSheet(XSSFSheet sheet, XSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        switch (config.getContentLocation()) {
            case HEADER:
                addXssfImageToHeader(sheet, workbook, pictureIdx, config);
                break;
            case FOOTER:
                addXssfImageToFooter(sheet, workbook, pictureIdx, config);
                break;
            case CONTENT:
                addXssfImageToContent(sheet, workbook, pictureIdx, config);
                break;
        }
    }

    /**
     * 处理HSSF格式（.xls）工作表
     */
    private void processHssfSheet(HSSFSheet sheet, HSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        switch (config.getContentLocation()) {
            case HEADER:
                addHssfImageToHeader(sheet, workbook, pictureIdx, config);
                break;
            case FOOTER:
                addHssfImageToFooter(sheet, workbook, pictureIdx, config);
                break;
            case CONTENT:
                addHssfImageToContent(sheet, workbook, pictureIdx, config);
                break;
        }
    }

    // ==================== XSSF 相关方法 ====================
    private void addXssfImageToHeader(XSSFSheet sheet, XSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        XSSFClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
        anchor.setRow1(0);
        anchor.setCol1(0);
        anchor.setDx2(unitsToEMU(300));
        anchor.setDy2(unitsToEMU(150));
        drawing.createPicture(anchor, pictureIdx);
    }

    private void addXssfImageToFooter(XSSFSheet sheet, XSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        XSSFClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
        int lastRow = sheet.getLastRowNum() > 0 ? sheet.getLastRowNum() : 10;
        anchor.setRow1(lastRow);
        anchor.setCol1(0);
        anchor.setDx2(unitsToEMU(300));
        anchor.setDy2(unitsToEMU(150));
        drawing.createPicture(anchor, pictureIdx);
    }

    private void addXssfImageToContent(XSSFSheet sheet, XSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);
        PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
        String relType = XSSFRelation.IMAGES.getRelation();
        //add relation from sheet to the picture data
        PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
        //set background picture to sheet
        sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
    }

    // ==================== HSSF 相关方法 ====================
    private void addHssfImageToHeader(HSSFSheet sheet, HSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        HSSFClientAnchor anchor = new HSSFClientAnchor();
        anchor.setRow1(0);
        anchor.setCol1(0);
        anchor.setDx2(unitsToEMU(300));
        anchor.setDy2(unitsToEMU(150));
        patriarch.createPicture(anchor, pictureIdx);
    }

    private void addHssfImageToFooter(HSSFSheet sheet, HSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        HSSFClientAnchor anchor = new HSSFClientAnchor();
        int lastRow = sheet.getLastRowNum() > 0 ? sheet.getLastRowNum() : 10;
        anchor.setRow1(lastRow);
        anchor.setCol1(0);
        anchor.setDx2(unitsToEMU(300));
        anchor.setDy2(unitsToEMU(150));
        patriarch.createPicture(anchor, pictureIdx);
    }

    private void addHssfImageToContent(HSSFSheet sheet, HSSFWorkbook workbook, int pictureIdx, WatermarkConfig config) {
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        HSSFClientAnchor anchor = new HSSFClientAnchor();
        anchor.setRow1(0);
        anchor.setCol1(0);
        int lastRow = sheet.getLastRowNum() > 0 ? sheet.getLastRowNum() : 50;
        int lastCol = sheet.getRow(0) != null ? sheet.getRow(0).getLastCellNum() : 20;
        anchor.setRow2(lastRow);
        anchor.setCol2(lastCol);
        HSSFPicture picture = patriarch.createPicture(anchor, pictureIdx);
        picture.resize(); // 自适应大小
    }

    // 单位转换：点（points）转EMU
    private int unitsToEMU(int points) {
        return (int) (points * 12700);
    }
}
    